﻿using System;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Globalization;

namespace System.Data
{
    /// <summary>
    /// Provides DataTableCollection functionality
    /// </summary>
    public class DataTableCollection : Collection<DataTable>
    {
        #region Events
        /// <summary>
        /// Another row was selected
        /// </summary>
        internal event EventHandler<DataSetEventArgs> AnotherRowWasSelected;

        /// <summary>
        /// Is reaised when DataSet schema was changed
        /// </summary>
        internal event EventHandler<DataSetEventArgs> SchemaChanged;

        /// <summary>
        /// INotifyPropertyChanged interface implementation
        /// </summary>
        internal event PropertyChangedEventHandler PropertyChanged;
        #endregion

        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        internal DataTableCollection()
        {
        }
        #endregion

        #region Indexers
        /// <summary>
        /// Gets DataTable with specified name
        /// </summary>
        /// <param name="name">DataTable name</param>
        /// <returns>DataTable if found, otherwise null</returns>
        public DataTable this[string name]
        {
            get
            {
                // Validate argument
                if (string.IsNullOrEmpty(name))
                {
                    throw new ArgumentNullException("name");
                }

                // Do case insensitive search
                string caseInsensitiveName = name.ToUpper(CultureInfo.InvariantCulture);
                foreach (DataTable dataTable in this)
                {
                    if (dataTable.TableName.ToUpper(CultureInfo.InvariantCulture).Equals(caseInsensitiveName))
                    {
                        return dataTable;
                    }
                }

                return null;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Adds DataTable to DataTableCollection
        /// </summary>
        /// <param name="dataTable">DataTable for adding</param>
        /// <returns>Added DataTable</returns>
        public new DataTable Add(DataTable dataTable)
        {
            // Validate argument
            if (dataTable == null)
            {
                throw new ArgumentNullException("dataTable");
            }

            if (string.IsNullOrEmpty(dataTable.TableName))
            {
                dataTable.TableName = "Table" + (base.Count + 1);
            }

            dataTable.AnotherRowWasSelected += new EventHandler<DataSetEventArgs>(DataTable_AnotherRowWasSelected);
            dataTable.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(DataTable_PropertyChanged);

            DataSetEventArgs dataSetEventArgs = new DataSetEventArgs();
            dataSetEventArgs.Command = "Add";
            OnSchemaChanged(dataTable, dataSetEventArgs);

            base.Add(dataTable);
            if (dataTable.HasErrors)
            {
                this.DataTable_PropertyChanged(dataTable, new PropertyChangedEventArgs("HasErrors"));
            }

            return dataTable;
        }

        /// <summary>
        /// Raises SchemaChanged event
        /// </summary>
        /// <param name="dataTable">Event source</param>
        /// <param name="dataSetEventArgs">Event arguments</param>
        private void OnSchemaChanged(DataTable dataTable, DataSetEventArgs dataSetEventArgs)
        {
            if (SchemaChanged != null)
            {
                SchemaChanged(dataTable, dataSetEventArgs);
            }
        }

        /// <summary>
        /// Removes DataTable from DataTableCollection
        /// </summary>
        /// <param name="dataTable">DataTable for removing</param>
        public new void Remove(DataTable dataTable)
        {
            // Validate argument
            if (dataTable == null)
            {
                throw new ArgumentNullException("dataTable");
            }

            DataSetEventArgs dataSetEventArgs = new DataSetEventArgs();
            dataSetEventArgs.Command = "Remove";
            OnSchemaChanged(dataTable, dataSetEventArgs);

            // Remove table
            dataTable.AnotherRowWasSelected -= DataTable_AnotherRowWasSelected;
            dataTable.PropertyChanged -= DataTable_PropertyChanged;
            base.Remove(dataTable);
        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Handles DataTable.AnotherRowWasSelected event
        /// </summary>
        /// <param name="sender">Event source</param>
        /// <param name="e">Event arguments</param>
        void DataTable_AnotherRowWasSelected(object sender, DataSetEventArgs e)
        {
            // Pass AnotherRowWasSelected event to DataSet for handling
            if (AnotherRowWasSelected != null)
            {
                AnotherRowWasSelected(sender, e);
            }
        }

        /// <summary>
        /// Handles DataTable.PropertyChanged event
        /// </summary>
        /// <param name="sender">Event source</param>
        /// <param name="e">Event arguments</param>
        void DataTable_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, e);
            }
        }
        #endregion
    }
}
